<?php

namespace console\db\channels;

use Yii;
use yii\db\Query;
use yii\helpers\Console;
use yii\helpers\ArrayHelper;
use yii\base\Exception;

/**
 * Migration自定义扩展
 * 
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
abstract class TransferMigration extends \console\db\Migration {

    /**
     * 是否先清理数据
     */
    public $truncateTableBefore = true;

    /**
     * 源数据库连接
     * @return \console\db\Connection 源数据库连接
     */
    public function getSourceDb() {
        return Yii::$app->olddb;
    }

    /**
     * @inheritdoc
     */
    public function safeUp() {
        $data = $this->getTableOptions();
        $count = count($data);
        Console::startProgress($i = 0, $count);
        foreach ($data as $name => $options) {
            if (!$this->isExistsTable($name)) {
                continue;
            }
            $this->batchSourceData($name, $options, $this->truncateTableBefore);
            Console::updateProgress( ++$i, $count);
        }
        Console::endProgress("update done." . PHP_EOL);
    }

    /**
     * @inheritdoc
     */
    public function safeDown() {
        foreach ($this->getTableOptions() as $key => $vls) {
            $tableName = '{{%' . $key . '}}';
            if (!$this->isExistsTable($tableName)) {
                continue;
            }
            $this->truncateTable($tableName);
        }
    }

    /**
     * @inheritdoc
     */
    public function batchSourceData($name, $options, $clear = true, Query $query = null) {
        $source = ArrayHelper::getValue($options, 'source');
        $db = null;
        if ($source) {
            $db = $this->getSourceDb();
        } else {
            $source = $name;
        }
        $fields = ArrayHelper::getValue($options, 'columns');
        $columns = [];
        while (list($key, $vls) = each($fields)) {
            if (is_string($key)) {
                $columns[] = $key;
            } elseif (is_numeric($key) && is_string($vls)) {
                $columns[] = $vls;
            } else {
                throw new Exception('错误');
            }
        }
        if (!($query && $query instanceof Query)) {
            $query = (new Query)->from('{{%' . $source . '}}');
        }
        $count = $query->count('*', $db);
        $i = 0;
        if (!$count) {
            return;
        }
        $tableName = '{{%' . $name . '}}';
        if ($clear !== false) {
            $this->truncateTable($tableName);
        }
        $size = ceil($count / static::BATCH_SIZE);
        Console::startProgress($i, $size, 'Counting objects: ', false);
        foreach ($query->batch(static::BATCH_SIZE, $db) as $rows) {
            $_trows = [];
            foreach ($rows as $row) {
                if (!$this->validateTransfer($row)) {
                    continue;
                }
                $_trow = $this->transfer($row, $fields);
                if ($_trow) {
                    $_trows[] = $_trow;
                }
            }
            $this->batchInsert($tableName, $columns, $_trows);
            Console::updateProgress(++$i, $size);
        }
        Console::endProgress("update done." . PHP_EOL);
        $this->afterTransfer($tableName);
    }

    /**
     * @inheritdoc
     */
    abstract public function getTableOptions();
}
